package br.com.vision.util.text;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.persistence.Entity;

import org.apache.commons.lang3.StringUtils;

import br.com.vision.util.reflection.ReflectionUtils;

public abstract class ConversaoString {

	public void converter(Object objeto) {
		Class<?> classe = objeto.getClass();
		if (!isClasseAnotada(classe)) {
			return;
		}

		percorreMetodos(classe, objeto);
	}

	private void percorreMetodos(Class<?> classe, Object objeto) {
		Method[] metodos = classe.getMethods();

		for (int i = 0; i < metodos.length; i++) {
			Method metodo = metodos[i];

			try {
				if (!isMetodoValido(metodo, objeto)) {
					continue;
				}

				alterarValoresObjeto(metodo, objeto, metodos);

			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
				e.printStackTrace();
				continue;
			}
		}
	}

	private void alterarValoresObjeto(Method metodo, Object objeto, Method[] metodos) throws IllegalAccessException, IllegalArgumentException,
			InvocationTargetException {
		String value = metodo.invoke(objeto).toString();

		value = converteValor(value);

		setValue(objeto, metodo, value, metodos);
	}

	protected abstract String converteValor(String value);

	protected abstract boolean isClasseAnotadaComAlteracaoDeValor(Class<?> clazz);

	private boolean isMetodoValido(Method metodo, Object objeto) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		if (!StringUtils.startsWith(metodo.getName(), "get")) {
			return false;
		}

		if (!metodo.getReturnType().equals(String.class)) {
			return false;
		}

		Object valorRetornadoMetodo = metodo.invoke(objeto);
		
		if(valorRetornadoMetodo == null){
			return false;
		}
		
		String value = valorRetornadoMetodo.toString();
		
		if (StringUtils.isEmpty(value)) {
			return false;
		}

		return true;
	}

	private boolean isClasseAnotada(Class<?> clazz) {
		if (!isClasseAnotadaComAlteracaoDeValor(clazz)) {
			return false;
		}

		if (!ReflectionUtils.isClasseAnotada(Entity.class, clazz)) {
			return false;
		}

		return true;
	}

	private void setValue(Object objeto, Method metodo, String upperCase, Method[] metodos) throws IllegalAccessException, IllegalArgumentException,
			InvocationTargetException {
		String setMetodo = metodo.getName();
		setMetodo = "s" + setMetodo.substring(1, setMetodo.length());

		for (int i = 0; i < metodos.length; i++) {
			Method metodoSetter = metodos[i];

			if (!StringUtils.equals(metodoSetter.getName(), setMetodo)) {
				continue;
			}

			metodoSetter.invoke(objeto, upperCase);
		}
	}

}
